package cn.life.common.utils.SM;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.io.IOException;
import java.math.BigInteger;

/**
 * @Description:
 * @Author 李佳明
 * @Date 2018-09-28 14:05
 */
public class SM2Utils {

    private static String pri = "";
    private static String pub = "";

    //生成随机秘钥对
    public static void generateKeyPair(){
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        //私钥
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        //公钥
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

        pri = Util.byteToHex(publicKey.getEncoded());
        pub = Util.byteToHex(privateKey.toByteArray());
        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));
        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));
    }

    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException
    {
        if (publicKey == null || publicKey.length == 0)
        {
            return null;
        }

        if (data == null || data.length == 0)
        {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Chiper cipher = new Chiper();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
//      System.out.println("C2 " + Util.byteToHex(source));
//      System.out.println("C3 " + Util.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
    {
        if (privateKey == null || privateKey.length == 0)
        {
            return null;
        }

        if (encryptedData == null || encryptedData.length == 0)
        {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = Util.byteToHex(encryptedData);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Chiper cipher = new Chiper();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);

        //返回解密结果
        return c2;
    }

    public static void main(String[] args) throws Exception
    {
        //生成密钥对
        //generateKeyPair();

        String plainText = "ererfeiisgod";
        byte[] sourceData = plainText.getBytes();

        //下面的秘钥可以使用generateKeyPair()生成的秘钥内容
        // 国密规范正式私钥
        String prik = "00EA08942001622937B94CD1E9FA8D236256F88C4B910F637057F2FD9A1DFCF658";
        // 国密规范正式公钥
        String pubk = "04E2462ECA73ECEEA7FB327695656955CBF0328B876E8D8AE2B12D7A0A104BEAFC4CFD887FCE2AA96540C741BF5918805958CB8BE1A1F8CC2F7AB50294EA8D0211";

        System.out.println("加密: ");
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);
        System.out.println(cipherText);
        System.out.println("解密: ");
        plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));
        System.out.println(plainText);

        System.out.println("********************************************************************************************************************************************************************");

        String test = "123";
        byte[] data = test.getBytes();

        System.out.println("加密: ");
        String testText = SM2Utils.encrypt(Util.hexToByte(pubk), data);
        System.out.println(cipherText);
        System.out.println("解密: ");
        plainText = new String(SM2Utils.decrypt(Util.hexToByte("9884F11A387C15EDA2FDA16DB93925A86F9C2E4657C2D7FE241A57F379C9144E"), Util.hexToByte("04F77657F0EDB82B84385F63706B702DC0938FAE2972FCAB9E6E78EFF3B96FF4C77CFCB1FA140672C825B7FFFB02A5EB180C5B7EEE77870DBF16700DD21116EA7BE3BC45D1C811178C7F511A57DC58C9EBB8DB8E7822B23FE8CB9294C547C7D9E34AF35CA13DA351ABAC38D822D8")));
        System.out.println(plainText);
    }
}
